/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jfonia.view.symbols;

import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import org.jfonia.connect5.basics.BasicValueNode;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.basics.Observer;
import org.jfonia.connect5.basics.ValueNode;
import org.jfonia.connect5.intervals.BasicDoubleInterval;
import org.jfonia.connect5.intervals.LinkedDoubleIntervalList;
import org.jfonia.connect5.relations.Equal;
import org.jfonia.constants.SymbolConstants;
import org.jfonia.model.elements.KeySignature;

/**
 *
 * @author Rik Bauwens
 */
public class KeySignatureSymbol extends ComplexStaffSymbol
{
        private KeySignature keySignature;
        private ValueNode<Integer> centralCRankNode;

        private IStaffSymbol[] accidentalSymbols;

        public KeySignatureSymbol(ValueNode<Double> frameX, ValueNode<Double> staffY,
                          MutableValueNode<Double> staffBase, MutableValueNode<Double> postStaffBase,
                          ValueNode<Double> xNode, MutableValueNode<Double> widthNode,
                          KeySignature keySignature, ValueNode<Integer> centralCRankNode)
        {
                super(frameX, staffY, staffBase, postStaffBase, xNode, widthNode,
                        new BasicValueNode<Integer>(SymbolConstants.KEY_SIGNATURE_RANK));
                this.keySignature = keySignature;
                this.centralCRankNode = centralCRankNode;
                init();
        }
        
        private void init()
        {
                //Initialize bounds
                rectangle = new Rectangle2D.Double(getX(), getY(), 0, 0);

                //Accidentals
                accidentalSymbols = makeAccidentals();
                rectangle.add(getAccidentalBounds());

                //Update nodes
                updateNodes();

                //Add observers
                keySignature.getTypeNode().addObserver(new Observer()
                {
                        public void onNotify(Object source)
                        {
                                //Create new bounds
                                rectangle = new Rectangle2D.Double(getX(), getY(), 0, 0);
                                //Recalculate accidentals
                                accidentalSymbols = makeAccidentals();
                                rectangle.add(getAccidentalBounds());
                                //Update the nodes
                                updateNodes();
                        }
                });
                centralCRankNode.addObserver(new Observer()
                {
                        public void onNotify(Object source)
                        {
                                //Create new bounds
                                rectangle = new Rectangle2D.Double(getX(), getY(), 0, 0);
                                //Recalculate accidentals
                                accidentalSymbols = makeAccidentals();
                                rectangle.add(getAccidentalBounds());
                                //Update the nodes
                                updateNodes();
                        }
                });
        }

        private IStaffSymbol[] makeAccidentals()
        {
                int accidentalType = (keySignature.getType() < 0 ?
                        SymbolConstants.ACCIDENTAL_FLAT : SymbolConstants.ACCIDENTAL_SHARP);
                IStaffSymbol[] res = new AccidentalSymbol[keySignature.getAccidentalCount()];

                LinkedDoubleIntervalList keySignatureWidth = new LinkedDoubleIntervalList();
                new Equal<Double>(getXNode(), keySignatureWidth.getBeginNode());
                for(int i = 0; i < keySignature.getAccidentalCount(); i++)
                {
                        BasicDoubleInterval accidentalWidth = new BasicDoubleInterval();
                        keySignatureWidth.add(accidentalWidth);
                        int rank = keySignature.getAccidental(i) + centralCRankNode.getValue();
                        res[i] = new AccidentalSymbol(getFrameX(), getStaffY(),
                                                      getStaffBase(), getPostStaffBase(),
                                                      accidentalWidth.getBeginNode(),
                                                      accidentalWidth.getDifferenceNode(),
                                                      new BasicValueNode<Integer>(rank),
                                                      new BasicValueNode<Integer>(accidentalType));
                }
                return res;
        }

        private Rectangle2D getAccidentalBounds()
        {
                return getBounds(accidentalSymbols);
        }

        //Prevent that the rank can be changed (fixed)
        @Override
        public void setRank(int rank) {}

        @Override
        public void paintSymbol(Graphics2D g)
        {
                super.paintSymbol(g);
                for(IStaffSymbol accidentalSymbol : accidentalSymbols)
                        accidentalSymbol.paintSymbol(g);
        }
}
